/*
 * Copyright (C) 2015 yydcdut (yuyidong2015@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.yydcdut.sdlv;

import com.alibaba.fastjson.JSON;
import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ListContainer;
import ohos.agp.database.DataSetSubscriber;
import ohos.app.Context;
import ohos.utils.PlainArray;

import java.util.HashMap;

/**
 * Created by yuyidong on 15/9/28.
 */
public class WrapperAdapter extends BaseItemProvider
        implements ItemMainLayout.OnItemSlideListenerProxy, Component.ClickedListener,
        ListContainer.ScrolledListener, ItemMainLayout.OnItemDeleteListenerProxy, Callback.OnDragDropListener,
        ItemMainLayout.OnItemScrollBackListenerProxy, ItemBackGroundLayout.OnMenuItemClickListener {
    /* 上下文 */
    private Context mContext;
    /* 适配器 */
    private BaseItemProvider mAdapter;
    /* 用户自定义参数 */
    private PlainArray<Menu> mMenuSparseArray;
    /* SDLV */
    private SlideListView mListView;
    /* 当前滑动的item的位置 */
    private int mSlideItemPosition = -1;
    /* 当前是否drag状态 */
    private boolean isInDragging;
    /* drag的entity */
    private Object mDraggedEntity;
    /* drag的entity的位置 */
    private int mDragEnteredEntityIndex = -1;
    /* 记录top位置 */
    private HashMap<Integer, Integer> mItemIdTopMap;
    /* drag的时候不移动的header */
    private int mStartLimit = -1;
    /* drag的时候不移动的footer */
    private int mEndLimit = Integer.MAX_VALUE;
    /* drag的动画时间 */
    private int mAnimationDuration = 300;
    /* 是否添加了Observer */
    private boolean isRegisterDataSetObserver;

    /* 监听器 */
    private OnAdapterSlideListenerProxy mOnAdapterSlideListenerProxy;
    private OnAdapterMenuClickListenerProxy mOnAdapterMenuClickListenerProxy;
    private onItemDeleteListenerProxy mOnItemDeleteListenerProxy;
    private OnScrollListenerProxy mOnScrollListenerProxy;
    private OnItemScrollBackListenerProxy mOnItemScrollBackListenerProxy;

    protected WrapperAdapter(Context context, SlideListView listView, BaseItemProvider adapter, PlainArray<Menu> sparseArray) {
        mContext = context;
        mListView = listView;
        mListView.setOnScrollListener(this);
        mAdapter = adapter;
        mMenuSparseArray = sparseArray;
        mListView.serAdapterDragDropListener(this);
        mItemIdTopMap = new HashMap<>();
        addDataSetObserver();
    }


    private DataSetSubscriber mDataSetObserver = new DataSetSubscriber() {
        @Override
        public void onChanged() {
            super.onChanged();
            returnSlideItemPosition();
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
        }
    };

    private void hide(Component itemMainLayout, int position) {
        if (mDraggedEntity == null) {
            if (itemMainLayout != null && itemMainLayout.getVisibility() != Component.VISIBLE) {
                itemMainLayout.setVisibility(Component.VISIBLE);
            }
            return;
        }
        if (getItem(position) == mDraggedEntity & itemMainLayout != null) {
            itemMainLayout.setVisibility(Component.INVISIBLE);
        } else if (itemMainLayout.getVisibility() != Component.VISIBLE) {
            itemMainLayout.setVisibility(Component.VISIBLE);
        }
    }

    /**
     * 创建Menu
     * @param menu 菜单对象
     * @param itemMainLayout 布局
     */
    private void createMenu(Menu menu, ItemMainLayout itemMainLayout) {
        if (menu.getTotalBtnLength(MenuItem.DIRECTION_LEFT) > 0) {
            for (int i = 0; i < menu.getMenuItems(MenuItem.DIRECTION_LEFT).size(); i++) {
                ItemBackGroundLayout itemBackGroundLayout = itemMainLayout.getItemLeftBackGroundLayout();
                itemBackGroundLayout.addMenuItem(menu.getMenuItems(MenuItem.DIRECTION_LEFT).get(i), i);
                itemBackGroundLayout.setDirection(MenuItem.DIRECTION_LEFT);
                itemBackGroundLayout.setOnMenuItemClickListener(this);
            }
        } else {
            itemMainLayout.getItemLeftBackGroundLayout().setVisibility(Component.HIDE);
        }
        if (menu.getTotalBtnLength(MenuItem.DIRECTION_RIGHT) > 0) {
            for (int i = 0; i < menu.getMenuItems(MenuItem.DIRECTION_RIGHT).size(); i++) {
                ItemBackGroundLayout itemBackGroundLayout = itemMainLayout.getItemRightBackGroundLayout();
                itemBackGroundLayout.addMenuItem(menu.getMenuItems(MenuItem.DIRECTION_RIGHT).get(i), i);
                itemBackGroundLayout.setDirection(MenuItem.DIRECTION_RIGHT);
                itemBackGroundLayout.setOnMenuItemClickListener(this);
            }
        } else {
            itemMainLayout.getItemRightBackGroundLayout().setVisibility(Component.HIDE);
        }
    }

    @Override
    public int getItemComponentType(int position) {
        return mAdapter.getItemComponentType(position);
    }

    @Override
    public int getComponentTypeCount() {
        return mAdapter.getComponentTypeCount();
    }

    /**
     * 设置slide滑开的item的位置
     *
     * @param position
     */
    protected void setSlideItemPosition(int position) {
        if (mSlideItemPosition != -1 && mSlideItemPosition != position) {
            returnSlideItemPosition();
        }
        if (mSlideItemPosition == position) {//已经执行过下面的操作了，就不要再去操作了。
            return;
        }
        mSlideItemPosition = position;
    }

    /**
     * 得到当前滑开的item的位置
     *
     * @return 获取item位置
     */
    protected int getSlideItemPosition() {
        return mSlideItemPosition;
    }

    /**
     * 归位mSlideItemPosition
     */
    protected void returnSlideItemPosition() {
        if (mSlideItemPosition != -1) {
            ItemMainLayout itemMainLayout = (ItemMainLayout) mListView.getComponentAt(mSlideItemPosition);
            if (itemMainLayout != null) {
                itemMainLayout.scrollBack();
            }
            mSlideItemPosition = -1;
        }
    }

    private void returnSlideItemPosition(ItemMainLayout.OnItemScrollBackListenerProxy onItemScrollBackListenerProxy) {
        if (mSlideItemPosition != -1) {
            ItemMainLayout itemMainLayout = (ItemMainLayout) mListView.getComponentAt(mSlideItemPosition);
            if (itemMainLayout != null) {
                itemMainLayout.scrollBack(onItemScrollBackListenerProxy);
            }
            mSlideItemPosition = -1;
        }
    }

    protected void deleteSlideItemPosition() {
        if (mSlideItemPosition != -1) {
            ItemMainLayout itemMainLayout = (ItemMainLayout) mListView.getComponentAt(mSlideItemPosition);
            if (itemMainLayout != null) {
                itemMainLayout.deleteItem(this);
            }
        }
    }

    /**
     * 返回item位置
     * @param x x坐标
     * @return 是否滑动归位了
     */
    protected int returnSlideItemPosition(float x) {
        if (mSlideItemPosition != -1) {
            ItemMainLayout itemMainLayout = (ItemMainLayout) mListView.getComponentAt(mSlideItemPosition);
            if (itemMainLayout != null) {
                int scrollBackSituation = itemMainLayout.scrollBack(x);
                switch (scrollBackSituation) {
                    case ItemMainLayout.SCROLL_BACK_ALREADY_CLOSED:
                    case ItemMainLayout.SCROLL_BACK_CLICK_OWN:
                        mSlideItemPosition = -1;
                        break;
                    case ItemMainLayout.SCROLL_BACK_CLICK_MENU_BUTTON:
                        break;
                }
                return scrollBackSituation;
            }
            mSlideItemPosition = -1;
            return ItemMainLayout.SCROLL_BACK_CLICK_NOTHING;
        }
        return ItemMainLayout.SCROLL_BACK_CLICK_NOTHING;
    }

    protected void slideItem(int position, int direction) {
        ItemMainLayout itemMainLayout = (ItemMainLayout) mListView.getComponentAt(position);
        if (itemMainLayout == null) {
            return;
        }
        mSlideItemPosition = position;
        itemMainLayout.scrollOpen(direction);
    }

    protected void addDataSetObserver() {
        if (mAdapter != null) {
            mAdapter.addDataSubscriber(mDataSetObserver);
            isRegisterDataSetObserver = true;
        }
    }

    protected void removeDataSetObserver() {
        if (mAdapter != null && isRegisterDataSetObserver) {
            mAdapter.removeDataSubscriber(mDataSetObserver);
            isRegisterDataSetObserver = false;
        }
    }

    /**
     * 设置监听器
     *
     * @param onAdapterSlideListenerProxy
     */
    protected void setOnAdapterSlideListenerProxy(OnAdapterSlideListenerProxy onAdapterSlideListenerProxy) {
        mOnAdapterSlideListenerProxy = onAdapterSlideListenerProxy;
    }

    public void onSlideOpen(Component view, int direction) {
        if (mOnAdapterSlideListenerProxy != null) {
            mOnAdapterSlideListenerProxy.onSlideOpen(view, mSlideItemPosition, direction);
        }
    }

    public void onSlideClose(Component view, int direction) {
        if (mOnAdapterSlideListenerProxy != null) {
            mOnAdapterSlideListenerProxy.onSlideClose(view, mSlideItemPosition, direction);
        }
    }

    /**
     * 设置监听器
     *
     * @param onAdapterMenuClickListenerProxy
     */
    protected void setOnAdapterMenuClickListenerProxy(OnAdapterMenuClickListenerProxy onAdapterMenuClickListenerProxy) {
        mOnAdapterMenuClickListenerProxy = onAdapterMenuClickListenerProxy;
    }



    @Override
    public void onDeleteBegin() {
        if (mOnItemDeleteListenerProxy != null) {
            mOnItemDeleteListenerProxy.onDeleteBegin();
        }
    }

    @Override
    public void onDelete(Component view) {
        int position = mSlideItemPosition;
        if (mSlideItemPosition != -1) {
            if (mOnItemDeleteListenerProxy != null) {
                mOnItemDeleteListenerProxy.onItemDelete(view, position);
            }
            mSlideItemPosition = -1;
            if (position == getCount() - 1) {
                mListView.invalidate();
            }
        }
    }

    protected void setStartLimit(int startLimit) {
        mStartLimit = startLimit;
    }

    protected void setEndLimit(int endLimit) {
        mEndLimit = endLimit;
    }

    private void setInDragging(boolean inDragging) {
        isInDragging = inDragging;
    }


    private void popDragEntry(int index) {
        if (isIndexInBound(index)) {
            mDraggedEntity = getItem(index);
            mDragEnteredEntityIndex = index;
            markDropArea(index, null);
        }
    }

    private void markDropArea(int itemIndex, SlideAndDragListView.OnDragDropListener listener) {
        if (mDraggedEntity != null && isIndexInBound(mDragEnteredEntityIndex) && isIndexInBound(itemIndex)) {
            if (listener != null) {
                listener.onDragDropViewMoved(mDragEnteredEntityIndex, itemIndex);
            }
            mDragEnteredEntityIndex = itemIndex;
        }
    }


    private boolean isIndexInBound(int itemIndex) {
        return itemIndex >= 0 && itemIndex < getCount();
    }


    @Override
    public boolean onDragStarted(int x, int y, Component view) {
//        int itemIndex = mListView.getIndexForComponent(view) - mListView.getHeaderViewsCount();
        int itemIndex = mListView.getIndexForComponent(view);
        if (itemIndex > mStartLimit && itemIndex < mEndLimit) {
            setInDragging(true);
            popDragEntry(itemIndex);
        } else {
            setInDragging(false);
        }
        return isInDragging;
    }

    @Override
    public void onDragMoving(int x, int y, Component view, SlideAndDragListView.OnDragDropListener listener) {
        if (view == null) {
            return;
        }
        int itemIndex = mListView.getIndexForComponent(view);
        if (isInDragging && mDragEnteredEntityIndex != itemIndex && isIndexInBound(itemIndex)
                && itemIndex > mStartLimit && itemIndex < mEndLimit) {
            markDropArea(itemIndex, listener);
        }
    }

    private SlideAndDragListView.OnDragDropListener onItemMoveCallBack;

    @Override
    public void onDragFinished(int x, int y, SlideAndDragListView.OnDragDropListener listener) {
        setInDragging(false);
        handleDrop(listener);
    }

    @Override
    public void onSetListener(SlideAndDragListView.OnDragDropListener listener) {
        onItemMoveCallBack = listener;
    }

    private void handleDrop(SlideAndDragListView.OnDragDropListener listener) {
        if (mDraggedEntity != null) {
            if (isIndexInBound(mDragEnteredEntityIndex)) {
                if (listener != null) {
                    listener.onDragViewDown(mDragEnteredEntityIndex);
                }
            }
            mDraggedEntity = null;
        }
    }

    @Override
    public void onClick(int position, int direction, Component view) {
        if (mOnAdapterMenuClickListenerProxy != null) {
            int scroll = mOnAdapterMenuClickListenerProxy.onMenuItemClick(view, mSlideItemPosition, position, direction);
            switch (scroll) {
                case Menu.ITEM_NOTHING:
                    break;
                case Menu.ITEM_SCROLL_BACK:
                    //归位
                    returnSlideItemPosition(this);
                    break;
                case Menu.ITEM_DELETE_FROM_BOTTOM_TO_TOP:
                    deleteSlideItemPosition();
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    public void onClick(Component component) {

    }

    @Override
    public void onContentScrolled(Component component, int firstVisibleItem, int visibleItemCount, int totalItemCount, int i3) {
        if (mOnScrollListenerProxy != null) {
            mOnScrollListenerProxy.onScrollProxy((ListContainer) component, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    @Override
    public void onScrollBack(Component view) {
        if (mOnItemScrollBackListenerProxy != null) {
            mOnItemScrollBackListenerProxy.onScrollBack(view, mListView.getIndexForComponent(view));
        }
    }


    @Override
    public int getCount() {
        return mAdapter.getCount();
    }

    @Override
    public Object getItem(int position) {
        return mAdapter.getItem(position);
    }

    @Override
    public long getItemId(int position) {
        return mAdapter.getItemId(position);
    }

    @Override
    public Component getComponent(int position, Component convertView, ComponentContainer componentContainer) {

        ItemMainLayout itemMainLayout = null;
        if (convertView == null) {
            Component contentView = mAdapter.getComponent(position, convertView, componentContainer);
            itemMainLayout = new ItemMainLayout(mContext, contentView);
            int type = mAdapter.getItemComponentType(position);
            Menu menu = mMenuSparseArray.get(type).get();
            if (menu == null) {
                throw new IllegalArgumentException("No menu matches any view types in ListView");
            }
            itemMainLayout.setParams(menu.getTotalBtnLength(MenuItem.DIRECTION_LEFT),
                    menu.getTotalBtnLength(MenuItem.DIRECTION_RIGHT), menu.isSlideOver());
            createMenu(menu, itemMainLayout);
            itemMainLayout.setOnItemSlideListenerProxy(this);
            itemMainLayout.setSelector(mListView.getBackgroundElement());
        } else {
            itemMainLayout = (ItemMainLayout) convertView;
            mAdapter.getComponent(position, itemMainLayout.getItemCustomView(), componentContainer);
        }

        hide(itemMainLayout, position);
        return itemMainLayout;
    }

    protected interface OnAdapterMenuClickListenerProxy {
        int onMenuItemClick(Component v, int itemPosition, int buttonPosition, int direction);
    }

    protected interface OnAdapterSlideListenerProxy {
        void onSlideOpen(Component view, int position, int direction);

        void onSlideClose(Component view, int position, int direction);
    }

    protected void setOnScrollListenerProxy(OnScrollListenerProxy onScrollListenerProxy) {
        mOnScrollListenerProxy = onScrollListenerProxy;
    }

    protected interface OnScrollListenerProxy {
        void onScrollStateChangedProxy(ListContainer view, int scrollState);

        void onScrollProxy(ListContainer view, int firstVisibleItem, int visibleItemCount, int totalItemCount);
    }

    protected void setOnItemDeleteListenerProxy(onItemDeleteListenerProxy onItemDeleteListenerProxy) {
        mOnItemDeleteListenerProxy = onItemDeleteListenerProxy;
    }

    protected interface onItemDeleteListenerProxy {
        void onDeleteBegin();

        void onItemDelete(Component view, int position);
    }

    public void setOnItemScrollBackListenerProxy(OnItemScrollBackListenerProxy onItemScrollBackListenerProxy) {
        mOnItemScrollBackListenerProxy = onItemScrollBackListenerProxy;
    }

    protected interface OnItemScrollBackListenerProxy {
        void onScrollBack(Component view, int position);
    }

    //TODO 长按 拖动 改变item位置回调
    @Override
    public void onItemMoved(int from, int to) {
        if (onItemMoveCallBack !=null){
            onItemMoveCallBack.onItemMoveFromTo(from, to);
        }
        super.onItemMoved(from, to);
    }
}
